namespace Angelus.Data.Linq.ProviderBase
{
    using System;
    using System.Collections.Generic;
    using System.Expressions;
    using System.Data.DLinq;
    using System.Data.DLinq.Expressions;
    using System.Data.DLinq.Provider;
    using System.Data.DLinq.ProviderBase;
    using System.Query;

    /// <summary>
    /// 
    /// </summary>
    internal class OracleQueryConverter
    {
        #region Fields

        private static Dictionary<string, int> _operators;
        private readonly SqlEval _evalBuilder;
        private readonly Dictionary<SqlNode, SqlSelect> _gmap;
        private readonly Dictionary<ParameterExpression, SqlNode> _map;
        private readonly DataServices _services;
        private readonly SqlFactory _sql;
        private readonly Translator _translator;
        private readonly TypeSystemProvider _typeProvider;
        private bool _allowDeferred;
        private Expression _dominatingExpression;
        private bool _outerNode;

        #endregion

        #region Constructors

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="evalBuilder"></param>
        /// <param name="typeProvider"></param>
        /// <param name="translator"></param>
        /// <param name="sql"></param>
        internal OracleQueryConverter(DataServices services, SqlEval evalBuilder, TypeSystemProvider typeProvider,
                                      Translator translator, SqlFactory sql)
        {
            this._services = services;
            this._evalBuilder = evalBuilder;
            this._translator = translator;
            this._sql = sql;
            this._typeProvider = typeProvider;
            this._map = new Dictionary<ParameterExpression, SqlNode>();
            this._gmap = new Dictionary<SqlNode, SqlSelect>();
            this._allowDeferred = true;
        }

        #endregion

        #region Query Conversion Implementation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="dominantExpression"></param>
        /// <returns></returns>
        internal SqlNode ConvertInner(Expression node, Expression dominantExpression)
        {
            this._dominatingExpression = dominantExpression;
            bool flag2 = this._outerNode;
            this._outerNode = false;
            SqlNode node2 = this.VisitInner(node);
            this._outerNode = flag2;
            return node2;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal SqlNode ConvertOuter(Expression node)
        {
            this._dominatingExpression = node;
            this._outerNode = true;
            SqlNode node2 = this.VisitInner(node);
            SqlExpression expression2 = node2 as SqlExpression;
            if (expression2 != null)
            {
                node2 = new SqlSelect(expression2, null, this._dominatingExpression);
            }
            return node2;
        }

        #endregion

        #region Private Implementation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t1"></param>
        /// <param name="t2"></param>
        /// <returns></returns>
        private bool CanIgnoreConversion(Type t1, Type t2)
        {
            t1 = TypeSystem.GetNonNullableType(t1);
            t2 = TypeSystem.GetNonNullableType(t2);
            if (t2.IsAssignableFrom(t1))
            {
                return true;
            }
            if (this._typeProvider.From(t1).IsRuntimeOnlyType || this._typeProvider.From(t2).IsRuntimeOnlyType)
            {
                return true;
            }
            ProviderType type3 = this._typeProvider.From(t1);
            ProviderType type4 = this._typeProvider.From(t2);
            if (type3 == type4)
            {
                return true;
            }
            TypeCode code3 = Type.GetTypeCode(t1);
            TypeCode code4 = Type.GetTypeCode(t2);
            switch (code3)
            {
                case TypeCode.SByte:
                    switch (code4)
                    {
                        case TypeCode.SByte:
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;

                case TypeCode.Byte:
                    switch (code4)
                    {
                        case TypeCode.Byte:
                        case TypeCode.Int16:
                        case TypeCode.UInt16:
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    return false;

                case TypeCode.Int16:
                    switch (code4)
                    {
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;

                        case TypeCode.UInt16:
                        case TypeCode.UInt32:
                        case TypeCode.UInt64:
                            goto Label_0164;
                    }
                    goto Label_0164;

                case TypeCode.UInt16:
                    switch (code4)
                    {
                        case TypeCode.UInt16:
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    return false;

                case TypeCode.Int32:
                    switch (code4)
                    {
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;

                        case TypeCode.UInt32:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                            goto Label_0194;
                    }
                    goto Label_0194;

                case TypeCode.UInt32:
                    switch (code4)
                    {
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;

                        case TypeCode.Single:
                            goto Label_021B;
                    }
                    goto Label_021B;

                case TypeCode.Int64:
                    switch (code4)
                    {
                        case TypeCode.Int64:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;

                        case TypeCode.UInt64:
                        case TypeCode.Single:
                            goto Label_01BC;
                    }
                    goto Label_01BC;

                case TypeCode.UInt64:
                    switch (code4)
                    {
                        case (TypeCode.UInt64 & TypeCode.Decimal):
                            return false;
                    }
                    return true;

                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                    switch (code4)
                    {
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    return false;

                default:
                    return (t1 == t2);
            }
            return false;
        Label_0164:
            return false;
        Label_0194:
            return false;
        Label_01BC:
            return false;
        Label_021B:
            return false;
        }


        private SqlNode ChangeType(SqlNode node, Type type)
        {
            SqlExpression expression2 = node as SqlExpression;
            if (((expression2 != null) && (type != typeof(object))) &&
                !this.CanIgnoreConversion(expression2.ClrType, type))
            {
                return this._sql.UnaryConvert(type, this._typeProvider.From(type), expression2,
                                             expression2.SourceExpression);
            }
            return node;
        }


        private static Expression ChooseBestDominatingExpression(Expression last, Expression next)
        {
            if (last != null)
            {
                if (next == null)
                {
                    return last;
                }
                if (next is MethodCallExpression)
                {
                    return next;
                }
                if (last is MethodCallExpression)
                {
                    return last;
                }
            }
            return next;
        }

        private SqlSelect CoerceToSequence(SqlNode node)
        {
            SqlSelect select2 = node as SqlSelect;
            if (select2 != null)
            {
                return select2;
            }
            if ((node.NodeType == SqlNodeType.Multiset) || (node.NodeType == SqlNodeType.Element))
            {
                return ((SqlSubSelect)node).Select;
            }
            if (node.NodeType == SqlNodeType.ClientArray)
            {
                throw new Exception("Constructed array sequences not supported yet.");
            }
            SqlExpression expression1 = (SqlExpression)node;
            SqlAlias alias1 = new SqlAlias(expression1);
            SqlAliasRef ref1 = new SqlAliasRef(alias1);
            return new SqlSelect(ref1, alias1, this._dominatingExpression);
        }


        private static Expression Decast(Expression exp)
        {
            while ((exp != null) && (exp.NodeType == ExpressionType.Cast))
            {
                exp = ((UnaryExpression)exp).Operand;
            }
            return exp;
        }

        private object Eval(SqlExpression expr)
        {
            return this._evalBuilder.Visit(expr).Eval();
        }

        private SqlSelect FindGroupSelect(SqlNode exp)
        {
            switch (exp.NodeType)
            {
                case SqlNodeType.AliasRef:
                    return this.FindGroupSelect(((SqlAliasRef)exp).Alias.Node);

                case SqlNodeType.Member:
                    return this.FindGroupSelect(((SqlMember)exp).Expression);

                case SqlNodeType.Select:
                    return this.FindGroupSelect(((SqlSelect)exp).Selection);
            }
            SqlSelect select1;
            this._gmap.TryGetValue(exp, out select1);
            return select1;
        }

        private SqlExpression GetAggregate(SqlNodeType aggType, Type clrType, SqlExpression exp)
        {
            ProviderType type2 = this._typeProvider.From(clrType);
            return new SqlUnary(aggType, clrType, type2, exp, this._dominatingExpression);
        }


        private List<SqlExpression> GetFunctionParameters(MethodCallExpression mce, MetaFunction function)
        {
            List<SqlExpression> list2 = new List<SqlExpression>(mce.Parameters.Count);
            MetaParameter[] parameterArray2 = function.GetParameters().ToArray();
            int num2 = 0;
            foreach (Expression expression1 in mce.Parameters)
            {
                SqlExpression expression2 = this.VisitExpression(expression1);
                MetaParameter parameter1 = parameterArray2[num2++];
                if (!string.IsNullOrEmpty(parameter1.DBType))
                {
                    SqlSimpleTypeExpression expression3 = expression2 as SqlSimpleTypeExpression;
                    if (expression3 != null)
                    {
                        ProviderType type1 = this._typeProvider.Parse(parameter1.DBType);
                        expression3.SetSqlType(type1);
                    }
                }
                list2.Add(expression2);
            }
            return list2;
        }


        private SqlTable GetSimpleSource(SqlSelect sel)
        {
            if (((sel.GroupBy.Count > 0) || (sel.Top != null)) || sel.IsDistinct)
            {
                return null;
            }
            SqlAlias alias2 = sel.From as SqlAlias;
            if (alias2 == null)
            {
                return null;
            }
            SqlTable table2 = alias2.Node as SqlTable;
            if (table2 != null)
            {
                return table2;
            }
            SqlSelect select2 = alias2.Node as SqlSelect;
            if (select2 == null)
            {
                return null;
            }
            return this.GetSimpleSource(select2);
        }


        private static ITable GetTable(Expression sequence)
        {
            ConstantExpression expression2 = sequence as ConstantExpression;
            if (expression2 != null)
            {
                return (expression2.Value as ITable);
            }
            return null;
        }

        private static bool IsConstNull(ConstantExpression expr)
        {
            return (expr.Value == null);
        }

        private bool IsSimpleSource(SqlSelect sel)
        {
            return (this.GetSimpleSource(sel) != null);
        }


        private SqlSelect LockSelect(SqlSelect sel)
        {
            if ((((sel.Selection.NodeType == SqlNodeType.AliasRef) && (sel.Where == null)) &&
                 ((sel.OrderBy.Count <= 0) && (sel.GroupBy.Count <= 0))) && ((sel.Having == null) && (sel.Top == null)))
            {
                return sel;
            }
            SqlAlias alias1 = new SqlAlias(sel);
            SqlAliasRef ref1 = new SqlAliasRef(alias1);
            return new SqlSelect(ref1, alias1, this._dominatingExpression);
        }

        private SqlNode TranslateConstantTable(ITable table)
        {
            MetaTable table2 = this._services.Model.GetTable(table.RowType);
            return this._translator.BuildDefaultQuery(table2.RowType, this._dominatingExpression, this._allowDeferred);
        }

        private SqlNode TranslateTableValuedFunction(MethodCallExpression mce, MetaFunction function)
        {
            List<SqlExpression> list2 = this.GetFunctionParameters(mce, function);
            SqlTableValuedFunctionCall call2 = this._sql.TableValuedFunctionCall(function.RowType, mce.Method.ReturnType,
                                                                                function.MappedName, list2, mce);
            SqlAlias alias2 = new SqlAlias(call2);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            SqlNew new2 = this._translator.BuildDefaultProjection(ref2, function.RowType,
                                                                 function.RowType.GetPersistentDataMembers(),
                                                                 this._allowDeferred, mce);
            return new SqlSelect(new2, alias2, mce);
        }

        internal SqlNode Visit(Expression node)
        {
            bool flag2 = this._outerNode;
            this._outerNode = false;
            SqlNode node2 = this.VisitInner(node);
            this._outerNode = flag2;
            return node2;
        }

        private SqlNode VisitAggregate(Expression sequence, LambdaExpression lambda, SqlNodeType aggType,
                                       Type returnType)
        {
            bool flag2 = (aggType == SqlNodeType.Count) || (aggType == SqlNodeType.LongCount);
            SqlNode node2 = this.Visit(sequence);
            SqlSelect select2 = this.CoerceToSequence(node2);
            SqlAlias alias2 = new SqlAlias(select2);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            if (lambda != null)
            {
                this._map[lambda.Parameters[0]] = ref2;
            }
            if (this._outerNode)
            {
                SqlExpression expression1 = (lambda != null) ? this.VisitExpression(lambda.Body) : null;
                SqlExpression expression2 = null;
                if (flag2 && (expression1 != null))
                {
                    expression2 = expression1;
                    expression1 = null;
                }
                else if ((expression1 == null) && !flag2)
                {
                    expression1 = ref2;
                }
                SqlSelect select3 = new SqlSelect(this.GetAggregate(aggType, returnType, expression1), alias2,
                                                  this._dominatingExpression);
                select3.Where = expression2;
                select3.OrderingType = SqlOrderingType.Never;
                return select3;
            }
            if (!flag2 || (lambda == null))
            {
                SqlSelect select4 = this.FindGroupSelect(node2);
                if (((select4 != null) && (select4.From is SqlAlias)) &&
                    (((SqlAlias)select4.From).Node.NodeType == SqlNodeType.Select))
                {
                    SqlExpression expression3 = null;
                    if (lambda != null)
                    {
                        SqlAlias alias3 = (SqlAlias)select4.From;
                        SqlAliasRef ref3 = new SqlAliasRef(alias3);
                        this._map[lambda.Parameters[0]] = ref3;
                        expression3 = this.VisitExpression(lambda.Body);
                    }
                    SqlExpression expression4 = this.GetAggregate(aggType, returnType, expression3);
                    SqlColumn column1 = new SqlColumn(expression4.ClrType, expression4.SqlType, null, expression4,
                                                      this._dominatingExpression);
                    select4.Row.Columns.Add(column1);
                    return new SqlColumnRef(column1);
                }
            }
            SqlExpression expression5 = (lambda != null) ? this.VisitExpression(lambda.Body) : null;
            SqlSelect select5 = new SqlSelect(this.GetAggregate(aggType, returnType, flag2 ? null : expression5), alias2,
                                              this._dominatingExpression);
            select5.Where = flag2 ? expression5 : null;
            return this._sql.SubSelect(SqlNodeType.ScalarSubSelect, select5);
        }


        private SqlNode VisitAs(UnaryExpression a)
        {
            SqlNode node2 = this.Visit(a.Operand);
            SqlExpression expression2 = node2 as SqlExpression;
            if (expression2 == null)
            {
                SqlSelect select2 = node2 as SqlSelect;
                if (select2 != null)
                {
                    SqlSubSelect select3 = this._sql.SubSelect(SqlNodeType.Multiset, select2);
                    return new SqlUnary(SqlNodeType.Treat, a.Type, this._typeProvider.From(a.Type), select3, a);
                }
                throw new Exception("Did not expect 'as' operator here '" + a + "'.");
            }
            return new SqlUnary(SqlNodeType.Treat, a.Type, this._typeProvider.From(a.Type), expression2, a);
        }

        private SqlNode VisitBinary(BinaryExpression b)
        {
            SqlExpression expression4 = this.VisitExpression(b.Left);
            SqlExpression expression5 = this.VisitExpression(b.Right);
            switch (b.NodeType)
            {
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                    return this._sql.Binary(SqlNodeType.Add, expression4, expression5);

                case ExpressionType.And:
                case ExpressionType.AndAlso:
                    return this._sql.Binary(SqlNodeType.And, expression4, expression5);

                case ExpressionType.BitwiseAnd:
                    return this._sql.Binary(SqlNodeType.BitAnd, expression4, expression5);

                case ExpressionType.BitwiseOr:
                    return this._sql.Binary(SqlNodeType.BitOr, expression4, expression5);

                case ExpressionType.BitwiseXor:
                    return this._sql.Binary(SqlNodeType.BitXor, expression4, expression5);

                case ExpressionType.Coalesce:
                    return this._sql.Binary(SqlNodeType.Coalesce, expression4, expression5);

                case ExpressionType.Divide:
                    return this._sql.Binary(SqlNodeType.Div, expression4, expression5);

                case ExpressionType.EQ:
                    return this._sql.Binary(SqlNodeType.EQ, expression4, expression5);

                case ExpressionType.GT:
                    return this._sql.Binary(SqlNodeType.GT, expression4, expression5);

                case ExpressionType.GE:
                    return this._sql.Binary(SqlNodeType.GE, expression4, expression5);

                case ExpressionType.LE:
                    return this._sql.Binary(SqlNodeType.LE, expression4, expression5);

                case ExpressionType.LShift:
                    {
                        SqlExpression expression7 = this._sql.FunctionCall(expression5.ClrType, "POWER",
                                                                          new SqlExpression[]
                                                                              {
                                                                                  this._sql.Literal(2,
                                                                                                   expression5.
                                                                                                       SourceExpression)
                                                                                  , expression5
                                                                              },
                                                                          expression5.SourceExpression);
                        return this._sql.Multiply(new SqlExpression[] { expression4, expression7 });
                    }
                case ExpressionType.LT:
                    return this._sql.Binary(SqlNodeType.LT, expression4, expression5);

                case ExpressionType.Modulo:
                    return this._sql.Binary(SqlNodeType.Mod, expression4, expression5);

                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    return this._sql.Binary(SqlNodeType.Mul, expression4, expression5);

                case ExpressionType.NE:
                    return this._sql.Binary(SqlNodeType.NE, expression4, expression5);

                case ExpressionType.Or:
                case ExpressionType.OrElse:
                    return this._sql.Binary(SqlNodeType.Or, expression4, expression5);

                case ExpressionType.RShift:
                    {
                        SqlExpression expression8 = this._sql.FunctionCall(expression5.ClrType, "POWER",
                                                                          new SqlExpression[]
                                                                              {
                                                                                  this._sql.Literal(2,
                                                                                                   expression5.
                                                                                                       SourceExpression)
                                                                                  , expression5
                                                                              },
                                                                          expression5.SourceExpression);
                        return this._sql.Divide(expression4, expression8);
                    }
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                    return this._sql.Binary(SqlNodeType.Sub, expression4, expression5);
            }
            throw new Exception("Binary operator not recognized");
        }

        private SqlNode VisitCast(UnaryExpression c)
        {
            return this.VisitChangeType(c.Operand, c.Type);
        }

        private SqlNode VisitChangeType(Expression expression, Type type)
        {
            SqlNode node2 = this.Visit(expression);
            return this.ChangeType(node2, type);
        }

        private SqlNode VisitConcat(Expression source1, Expression source2)
        {
            SqlSelect select3 = this.VisitSequence(source1);
            SqlSelect select4 = this.VisitSequence(source2);
            SqlUnion union2 = new SqlUnion(select3, select4, true);
            SqlAlias alias2 = new SqlAlias(union2);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            return new SqlSelect(ref2, alias2, this._dominatingExpression);
        }

        private SqlExpression VisitConditional(ConditionalExpression cond)
        {
            List<SqlWhen> list2 = new List<SqlWhen>(1);
            Expression expression2 = cond;
            while (expression2.NodeType == ExpressionType.Conditional)
            {
                cond = (ConditionalExpression)expression2;
                list2.Add(new SqlWhen(this.VisitExpression(cond.Test), this.VisitExpression(cond.IfTrue)));
                expression2 = cond.IfFalse;
            }
            return this._sql.SearchedCase(list2.ToArray(), this.VisitExpression(expression2), this._dominatingExpression);
        }

        private SqlNode VisitConstant(ConstantExpression cons)
        {
            ITable table2 = cons.Value as ITable;
            if (table2 != null)
            {
                return this.TranslateConstantTable(table2);
            }
            IQueryable queryable2 = cons.Value as IQueryable;
            if (queryable2 != null)
            {
                return this.Visit(queryable2.Expression);
            }
            Type type2 = cons.Type;
            if (IsConstNull(cons))
            {
                return new SqlLiteral(type2, this._typeProvider.From(type2), null, this._dominatingExpression);
            }
            if (type2 == typeof(bool))
            {
                return this._sql.Literal(cons.Value, this._dominatingExpression);
            }
            SqlClientParameter parameter1 = new SqlClientParameter(type2, this._typeProvider.From(type2), cons.Value,
                                                                   this._dominatingExpression);
            return this._sql.Unary(SqlNodeType.ClientExpression, parameter1, this._dominatingExpression);
        }

        private SqlNode VisitContains(Expression sequence, Expression value)
        {
            ParameterExpression expression3 = Expression.Parameter(value.Type, "p");
            LambdaExpression expression4 = QueryExpression.Lambda(Expression.EQ(expression3, value),
                                                                  new ParameterExpression[] { expression3 });
            return this.VisitQuantifier(sequence, expression4, true);
        }

        private SqlSelect VisitDefaultIfEmpty(Expression sequence)
        {
            SqlSelect select4 = this.VisitSequence(sequence);
            SqlAlias alias3 = new SqlAlias(select4);
            SqlAliasRef ref2 = new SqlAliasRef(alias3);
            SqlExpression expression3 =
                new SqlOptionalValue(
                    new SqlColumn("test",
                                  new SqlLiteral(typeof(int?), this._typeProvider.From(typeof(int)), 1,
                                                 this._dominatingExpression)), ref2);
            SqlSelect select5 = new SqlSelect(expression3, alias3, this._dominatingExpression);
            alias3 = new SqlAlias(select5);
            ref2 = new SqlAliasRef(alias3);
            SqlExpression expression4 = this._sql.Literal(null, this._dominatingExpression);
            SqlSelect select6 = new SqlSelect(expression4, null, this._dominatingExpression);
            SqlAlias alias4 = new SqlAlias(select6);
            new SqlAliasRef(alias4);
            SqlJoin join2 = new SqlJoin(SqlJoinType.OuterApply, alias4, alias3, null, this._dominatingExpression);
            return new SqlSelect(ref2, join2, this._dominatingExpression);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="qd"></param>
        /// <returns></returns>
        private SqlStatement VisitDelete(DeleteCommand qd)
        {
            SqlSelect select2 = this.VisitSequence(qd.Sequence);
            Type type2 = TypeSystem.GetElementType(qd.Sequence.Type);
            if (!this.IsSimpleSource(select2))
            {
                throw new Exception("Cannot delete types of " + type2);
            }
            return new SqlDelete(select2, qd);
        }


        private SqlSelect VisitDistinct(Expression sequence)
        {
            SqlSelect select2 = this.LockSelect(this.VisitSequence(sequence));
            select2.IsDistinct = true;
            return select2;
        }

        private SqlNode VisitExcept(Expression source1, Expression source2)
        {
            Type type2 = TypeSystem.GetElementType(source1.Type);
            ParameterExpression expression4 = Expression.Parameter(type2, "a");
            ParameterExpression expression5 = Expression.Parameter(type2, "b");
            Expression expression6 =
                QueryExpression.Distinct(QueryExpression.Where(source1,
                                                               QueryExpression.Lambda(
                                                                   Expression.Not(QueryExpression.Any(source2,
                                                                                                      QueryExpression.
                                                                                                          Lambda(
                                                                                                          Expression.EQ(
                                                                                                              expression4,
                                                                                                              expression5),
                                                                                                          new ParameterExpression
                                                                                                              []
                                                                                                              {
                                                                                                                  expression5
                                                                                                              }))),
                                                                   new ParameterExpression[] { expression4 })));
            return this.Visit(expression6);
        }

        private SqlExpression VisitExpression(Expression exp)
        {
            SqlNode node2 = this.Visit(exp);
            if (node2 != null)
            {
                SqlExpression expression2 = node2 as SqlExpression;
                if (expression2 == null)
                {
                    SqlSelect select2 = node2 as SqlSelect;
                    if (select2 == null)
                    {
                        throw new Exception("Unexpected node type: " + node2);
                    }
                    return this._sql.SubSelect(SqlNodeType.Multiset, select2);
                }
                return expression2;
            }
            return null;
        }

        private SqlNode VisitFirst(Expression sequence, LambdaExpression lambda, bool isFirst)
        {
            SqlSelect select3 = this.LockSelect(this.VisitSequence(sequence));
            if (lambda != null)
            {
                this._map[lambda.Parameters[0]] = select3.Selection;
                select3.Where = this.VisitExpression(lambda.Body);
            }
            if (isFirst)
            {
                select3.Top = this._sql.Literal(1, this._dominatingExpression);
            }
            if (this._outerNode)
            {
                return select3;
            }
            SqlNodeType type2 = this._typeProvider.From(select3.Selection.ClrType).IsRuntimeOnlyType
                                    ? SqlNodeType.Element
                                    : SqlNodeType.ScalarSubSelect;
            return this._sql.SubSelect(type2, select3);
        }

        private SqlNode VisitFunclet(FuncletExpression func)
        {
            return this.VisitConstant(Expression.Constant(func.Funclet()));
        }


        private SqlNode VisitGroupBy(Expression sequence, LambdaExpression keyLambda, LambdaExpression elemLambda)
        {
            SqlSelect select7 = this.VisitSequence(sequence);
            select7 = this.LockSelect(select7);
            SqlAlias alias4 = new SqlAlias(select7);
            SqlAliasRef ref3 = new SqlAliasRef(alias4);
            this._map[keyLambda.Parameters[0]] = ref3;
            SqlExpression expression6 = this.VisitExpression(keyLambda.Body);
            SqlDuplicator duplicator2 = new SqlDuplicator();
            SqlSelect select8 = (SqlSelect)duplicator2.Duplicate(select7);
            SqlAlias alias5 = new SqlAlias(select8);
            SqlAliasRef ref4 = new SqlAliasRef(alias5);
            this._map[keyLambda.Parameters[0]] = ref4;
            SqlExpression expression7 = this.VisitExpression(keyLambda.Body);
            SqlExpression expression8;
            if (elemLambda != null)
            {
                this._map[elemLambda.Parameters[0]] = ref4;
                expression8 = this.VisitExpression(elemLambda.Body);
            }
            else
            {
                expression8 = ref4;
            }
            SqlSubExpression expression9 = new SqlSubExpression(expression6);
            expression6 = new SqlSubExpressionRef(expression9);
            SqlSelect select9 = new SqlSelect(expression8, alias5, this._dominatingExpression);
            select9.Where = this._sql.Binary(SqlNodeType.EQ, expression6, expression7);
            SqlSubSelect select10 = this._sql.SubSelect(SqlNodeType.Multiset, select9);
            SqlSelect select11 = new SqlSelect(ref3, alias4, this._dominatingExpression);
            select11.GroupBy.Add(expression9);
            SqlAlias alias6 = new SqlAlias(select11);
            Type type2 = typeof(IGrouping<,>).MakeGenericType(new Type[] { expression6.ClrType, expression8.ClrType });
            SqlExpression expression10 = new SqlGrouping(type2, this._typeProvider.From(type2), expression6, select10,
                                                         this._dominatingExpression);
            SqlSelect select12 = new SqlSelect(expression10, alias6, this._dominatingExpression);
            if (expression8 == ref4)
            {
                this._gmap[expression10] = select11;
            }
            return select12;
        }

        private SqlSelect VisitGroupJoin(Expression outerSequence, Expression innerSequence,
                                         LambdaExpression outerKeySelector, LambdaExpression innerKeySelector,
                                         LambdaExpression resultSelector)
        {
            SqlSelect select5 = this.VisitSequence(outerSequence);
            SqlSelect select6 = this.VisitSequence(innerSequence);
            SqlAlias alias3 = new SqlAlias(select5);
            SqlAliasRef ref3 = new SqlAliasRef(alias3);
            SqlAlias alias4 = new SqlAlias(select6);
            SqlAliasRef ref4 = new SqlAliasRef(alias4);
            this._map[outerKeySelector.Parameters[0]] = ref3;
            SqlExpression expression5 = this.VisitExpression(outerKeySelector.Body);
            this._map[innerKeySelector.Parameters[0]] = ref4;
            SqlExpression expression6 = this.VisitExpression(innerKeySelector.Body);
            SqlExpression expression7 = this._sql.Binary(SqlNodeType.EQ, expression5, expression6);
            SqlSelect select7 = new SqlSelect(ref4, alias4, this._dominatingExpression);
            select7.Where = expression7;
            SqlSubSelect select8 = this._sql.SubSelect(SqlNodeType.Multiset, select7);
            this._map[resultSelector.Parameters[0]] = ref3;
            this._map[resultSelector.Parameters[1]] = select8;
            SqlExpression expression8 = this.VisitExpression(resultSelector.Body);
            return new SqlSelect(expression8, alias3, this._dominatingExpression);
        }

        private SqlIncludeMember VisitIncludeItem(Expression root, Expression exp)
        {
            exp = Decast(exp);
            MethodCallExpression expression2 = exp as MethodCallExpression;
            if (expression2 == null)
            {
                return this.VisitIncludeMember(root, exp, null);
            }
            if ((!expression2.Method.IsStatic || (expression2.Method.Name != "Including")) ||
                (expression2.Method.DeclaringType != typeof(DataQueryExtensions)))
            {
                throw new IncludeException();
            }
            SqlIncludeMember member1 = this.VisitIncludeMember(root, expression2.Parameters[0], null);
            this.VisitIncludeList(((NewArrayExpression)expression2.Parameters[1]).Expressions, member1.Includes);
            return member1;
        }

        private void VisitIncludeList(IEnumerable<Expression> incs, ICollection<SqlIncludeMember> list)
        {
            foreach (LambdaExpression expression1 in incs)
            {
                Expression expression2 = Decast(expression1.Body);
                list.Add(this.VisitIncludeItem(expression1.Parameters[0], expression2));
            }
        }


        private SqlIncludeMember VisitIncludeMember(Expression root, Expression exp, SqlIncludeMember outer)
        {
            exp = Decast(exp);
            MemberExpression expression2 = exp as MemberExpression;
            if (expression2 == null)
            {
                throw new IncludeException();
            }
            SqlIncludeMember member2 = new SqlIncludeMember(expression2.Member, this._dominatingExpression);
            if (outer != null)
            {
                member2.Includes.Add(outer);
            }
            exp = Decast(expression2.Expression);
            if (exp != root)
            {
                return this.VisitIncludeMember(root, exp, member2);
            }
            return member2;
        }


        private SqlNode VisitIncluding(Expression sequence, IEnumerable<Expression> expressions)
        {
            SqlSelect select2 = this.VisitSequence(sequence);
            SqlAlias alias2 = new SqlAlias(select2);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            SqlIncluding including2 = this._sql.Including(ref2, this._dominatingExpression);
            this.VisitIncludeList(expressions, including2.Includes);
            return new SqlSelect(including2, alias2, this._dominatingExpression);
        }

        private SqlNode VisitInner(Expression node)
        {
            //SqlNode node1;
            if (node == null)
            {
                return null;
            }
            Expression expression2 = this._dominatingExpression;
            this._dominatingExpression = ChooseBestDominatingExpression(this._dominatingExpression, node);
            try
            {
                switch (node.NodeType)
                {
                    case ExpressionType.Add:
                    case ExpressionType.AddChecked:
                    case ExpressionType.And:
                    case ExpressionType.AndAlso:
                    case ExpressionType.BitwiseAnd:
                    case ExpressionType.BitwiseOr:
                    case ExpressionType.BitwiseXor:
                    case ExpressionType.Coalesce:
                    case ExpressionType.Divide:
                    case ExpressionType.EQ:
                    case ExpressionType.GT:
                    case ExpressionType.GE:
                    case ExpressionType.LE:
                    case ExpressionType.LShift:
                    case ExpressionType.LT:
                    case ExpressionType.Modulo:
                    case ExpressionType.Multiply:
                    case ExpressionType.MultiplyChecked:
                    case ExpressionType.NE:
                    case ExpressionType.Or:
                    case ExpressionType.OrElse:
                    case ExpressionType.RShift:
                    case ExpressionType.Subtract:
                    case ExpressionType.SubtractChecked:
                        return this.VisitBinary((BinaryExpression)node);

                    case ExpressionType.As:
                        return this.VisitAs((UnaryExpression)node);

                    case ExpressionType.BitwiseNot:
                    case ExpressionType.Negate:
                    case ExpressionType.Not:
                        return this.VisitUnary((UnaryExpression)node);

                    case ExpressionType.Cast:
                    case ExpressionType.Convert:
                    case ExpressionType.ConvertChecked:
                        return this.VisitCast((UnaryExpression)node);

                    case ExpressionType.Conditional:
                        return this.VisitConditional((ConditionalExpression)node);

                    case ExpressionType.Constant:
                        return this.VisitConstant((ConstantExpression)node);

                    case ExpressionType.Funclet:
                        return this.VisitFunclet((FuncletExpression)node);

                    case ExpressionType.Invoke:
                        return this.VisitInvocation((InvocationExpression)node);

                    case ExpressionType.Is:
                        return this.VisitTypeBinary((TypeBinaryExpression)node);

                    case ExpressionType.MemberAccess:
                        return this.VisitMemberAccess((MemberExpression)node);

                    case ExpressionType.MemberInit:
                        return this.VisitMemberInit((MemberInitExpression)node);

                    case ExpressionType.MethodCall:
                    case ExpressionType.MethodCallVirtual:
                        return this.VisitMethodCall((MethodCallExpression)node);

                    case ExpressionType.New:
                        return this.VisitNew((NewExpression)node);

                    case ExpressionType.NewArrayInit:
                        return this.VisitNewArrayInit((NewArrayExpression)node);

                    case ExpressionType.Parameter:
                        return this.VisitParameter((ParameterExpression)node);

                    case ExpressionType.Quote:
                        return this.Visit(((UnaryExpression)node).Operand);

                    case ((ExpressionType)0x3e8):
                        return this.VisitDelete((DeleteCommand)node);

                    case ((ExpressionType)0x3e9):
                        return this.VisitInsert((InsertCommand)node);

                    case ((ExpressionType)0x3ea):
                        return this.VisitUpdate((UpdateCommand)node);

                    case ((ExpressionType)0x3eb):
                        return this.VisitUserQuery((UserQueryExpression)node);

                    case ((ExpressionType)0x7d0):
                        return ((KnownExpression)node).Node;
                }
                throw new Exception("Unrecognized expression node: " + node.NodeType);
            }
            finally
            {
                this._dominatingExpression = expression2;
            }
            //return node1;
        }

        private SqlStatement VisitInsert(InsertCommand qi)
        {
            ITable table4 = GetTable(qi.Sequence);
            if (table4 == null)
            {
                throw new Exception("Insert source must be a table");
            }
            MetaTable table5 = this._services.Model.GetTable(table4.RowType);
            MetaType type2 = table5.RowType.GetInheritanceType(qi.Item.Type);
            SqlTable table6 = this._sql.Table(table5, table5.RowType, this._dominatingExpression);
            MemberInitExpression expression5 = qi.Item as MemberInitExpression;
            if (expression5 == null)
            {
                throw new Exception("Inserted item must be a MemberInitExpresion");
            }
            if (expression5.NewExpression.Args.Count != 0)
            {
                throw new Exception("Inserted item must not have constructor args");
            }
            List<SqlMemberAssign> list2 = new List<SqlMemberAssign>(expression5.Bindings.Count);
            using (IEnumerator<Binding> enumerator1 = expression5.Bindings.GetEnumerator())
            {
                while (enumerator1.MoveNext())
                {
                    Binding binding1 = enumerator1.Current;
                    MemberAssignment assignment1 = binding1 as MemberAssignment;
                    if (assignment1 == null)
                    {
                        throw new InvalidOperationException(string.Format("Unhandled binding type: {0}",
                                                                          binding1.BindingType));
                    }
                    SqlExpression expression9 = this.VisitExpression(assignment1.Expression);
                    MetaDataMember member1 = type2.GetDataMember(assignment1.Member);
                    ProviderType type3 = this._sql.Default(member1);
                    if (!type3.IsSameTypeFamily(expression9.SqlType))
                    {
                        expression9 = this._sql.UnaryConvert(expression9.ClrType, type3, expression9,
                                                            expression9.SourceExpression);
                    }
                    list2.Add(new SqlMemberAssign(assignment1.Member, expression9));
                }
            }
            SqlNew new2 = this._sql.New(type2, expression5.NewExpression.Constructor, null, list2, qi);
            SqlInsert insert2 = new SqlInsert(table6, new2, qi);
            if (qi.Result == null)
            {
                return insert2;
            }

            OracleRefCursor cursor = new OracleRefCursor(this._dominatingExpression);
            cursor.Parameter = new SqlParameter(typeof(object), this._typeProvider.Parse("cursor"), "p",
                                                this._dominatingExpression);

            SqlAlias alias2 = new SqlAlias(table6);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            LambdaExpression expression6 = qi.Result;
            this._map.Add(expression6.Parameters[0], ref2);
            SqlExpression expression7 = this.VisitExpression(expression6.Body);
            SqlExpression expression8;
            if (type2.AutoGenMember != null)
            {
                cursor.Locals.Columns.Add(new SqlColumn(typeof(decimal), this._typeProvider.Parse("number"), "IDENTITY",
                                                        null, this._dominatingExpression));
                //expression8 = this._sql.Binary(SqlNodeType.EQ, this._sql.Member(ref2, type2.AutoGenMember.Member), (SqlExpression)this.ChangeType(new SqlVariable(typeof(decimal), this._typeProvider.From(typeof(decimal)), "@@IDENTITY", qi), type2.AutoGenMember.MemberType));
                expression8 = this._sql.Binary(SqlNodeType.EQ, this._sql.Member(ref2, type2.AutoGenMember.Member),
                                              (SqlExpression)
                                              this.ChangeType(
                                                  new SqlVariable(typeof(decimal),
                                                                  this._typeProvider.From(typeof(decimal)), "IDENTITY",
                                                                  qi), type2.AutoGenMember.MemberType));
                string[] arguments = type2.AutoGenMember.DBType.Split(' ');
                string queryText = string.Format("SELECT {0}.CURRVAL INTO {1} FROM DUAL; ",
                                                 arguments[arguments.Length - 1], "IDENTITY");
                cursor.UserQuery = new SqlUserQuery(queryText, null, null, this._dominatingExpression);
            }
            else
            {
                expression8 = this._sql.Binary(SqlNodeType.EQ, ref2, insert2.Expression);
            }
            SqlSelect select2 = new SqlSelect(expression7, alias2, qi);
            select2.Where = expression8;
            cursor.Select = select2;
            SqlBlock block2 = new SqlBlock(this._dominatingExpression);
            block2.Statements.Add(insert2);
            block2.Statements.Add(cursor);

            return block2;
        }


        private SqlNode VisitIntersect(Expression source1, Expression source2)
        {
            Type type2 = TypeSystem.GetElementType(source1.Type);
            ParameterExpression expression4 = Expression.Parameter(type2, "a");
            ParameterExpression expression5 = Expression.Parameter(type2, "b");
            Expression expression6 =
                QueryExpression.Distinct(QueryExpression.Where(source1,
                                                               QueryExpression.Lambda(
                                                                   QueryExpression.Any(source2,
                                                                                       QueryExpression.Lambda(
                                                                                           Expression.EQ(expression4,
                                                                                                         expression5),
                                                                                           new ParameterExpression[] { expression5 })),
                                                                   new ParameterExpression[] { expression4 })));
            return this.Visit(expression6);
        }


        private SqlNode VisitInvocation(InvocationExpression invoke)
        {
            int num1 = 0;
            int num2 = invoke.Args.Count;
            while (num1 < num2)
            {
                this._map[invoke.Expression.Parameters[num1]] = this.Visit(invoke.Args[num1]);
                num1++;
            }
            return this.VisitInner(invoke.Expression.Body);
        }

        private SqlSelect VisitJoin(Expression outerSequence, Expression innerSequence,
                                    LambdaExpression outerKeySelector, LambdaExpression innerKeySelector,
                                    LambdaExpression resultSelector)
        {
            SqlSelect select4 = this.VisitSequence(outerSequence);
            SqlSelect select5 = this.VisitSequence(innerSequence);
            SqlAlias alias3 = new SqlAlias(select4);
            SqlAliasRef ref3 = new SqlAliasRef(alias3);
            SqlAlias alias4 = new SqlAlias(select5);
            SqlAliasRef ref4 = new SqlAliasRef(alias4);
            this._map[outerKeySelector.Parameters[0]] = ref3;
            SqlExpression expression5 = this.VisitExpression(outerKeySelector.Body);
            this._map[innerKeySelector.Parameters[0]] = ref4;
            SqlExpression expression6 = this.VisitExpression(innerKeySelector.Body);
            this._map[resultSelector.Parameters[0]] = ref3;
            this._map[resultSelector.Parameters[1]] = ref4;
            SqlExpression expression7 = this.VisitExpression(resultSelector.Body);
            SqlExpression expression8 = this._sql.Binary(SqlNodeType.EQ, expression5, expression6);
            SqlJoin join2 = new SqlJoin(SqlJoinType.Cross, alias3, alias4, null, this._dominatingExpression);
            SqlSelect select6 = new SqlSelect(expression7, join2, this._dominatingExpression);
            select6.Where = expression8;
            return select6;
        }

        private SqlNode VisitMemberAccess(MemberExpression ma)
        {
            if ((ma.Member.Name == "Count") && TypeSystem.IsSequenceType(ma.Expression.Type))
            {
                return this.VisitAggregate(ma.Expression, null, SqlNodeType.Count, typeof(decimal));
            }
            return this._sql.Member(this.VisitExpression(ma.Expression), ma.Member);
        }

        private SqlExpression VisitMemberInit(MemberInitExpression init)
        {
            MetaTable table2 = this._services.Model.GetTable(init.Type);
            MetaType type2 = (table2 != null)
                                 ? table2.RowType.GetInheritanceType(init.Type)
                                 : this._services.Model.GetUnmappedType(init.Type);
            SqlExpression[] expressionArray2 = null;
            NewExpression expression2 = init.NewExpression;
            if ((expression2.Type == typeof(decimal)) && (expression2.Args.Count == 1))
            {
                return (this.VisitCast(Expression.Cast(expression2.Args[0], typeof(decimal))) as SqlExpression);
            }
            if (expression2.Args.Count > 0)
            {
                expressionArray2 = new SqlExpression[expression2.Args.Count];
                int num3 = 0;
                int num4 = expressionArray2.Length;
                while (num3 < num4)
                {
                    expressionArray2[num3] = this.VisitExpression(expression2.Args[num3]);
                    num3++;
                }
            }
            int num2 = init.Bindings.Count;
            SqlMemberAssign[] assignArray2 = new SqlMemberAssign[num2];
            int[] numArray2 = new int[assignArray2.Length];
            for (int num5 = 0; num5 < num2; num5++)
            {
                MemberAssignment assignment1 = init.Bindings[num5] as MemberAssignment;
                if (assignment1 == null)
                {
                    throw new InvalidOperationException(string.Format("Unhandled binding type: {0}",
                                                                      init.Bindings[num5].BindingType));
                }
                SqlExpression expression3 = this.VisitExpression(assignment1.Expression);
                SqlMemberAssign assign1 = new SqlMemberAssign(assignment1.Member, expression3);
                assignArray2[num5] = assign1;
                numArray2[num5] = type2.GetDataMember(assignment1.Member).Ordinal;
            }
            Array.Sort(numArray2, assignArray2, 0, assignArray2.Length);
            return this._sql.New(type2, expression2.Constructor, expressionArray2, assignArray2,
                                this._dominatingExpression);
        }

        private SqlNode VisitMethodCall(MethodCallExpression mc)
        {
            Type type2 = mc.Method.DeclaringType;
            if (mc.Method.IsStatic)
            {
                if (((type2 == typeof(Sequence)) || (type2 == typeof(Queryable))) ||
                    (type2 == typeof(DataQueryExtensions)))
                {
                    SqlNode node1 = this.VisitSequenceOperatorCall(mc);
                    if (node1 != null)
                    {
                        return node1;
                    }
                }
                else if (((type2 == typeof(DBConvert)) || (type2 == typeof(Convert))) &&
                         (mc.Method.Name == "ChangeType"))
                {
                    ConstantExpression expression3 = mc.Parameters[1] as ConstantExpression;
                    if ((expression3 != null) && (expression3.Value != null))
                    {
                        return this.VisitChangeType(mc.Parameters[0], (Type)expression3.Value);
                    }
                }
            }
            else if (typeof(DataContext).IsAssignableFrom(mc.Method.DeclaringType) ||
                     typeof(Schema).IsAssignableFrom(mc.Method.DeclaringType))
            {
                MetaFunction function1 = this._services.Model.GetFunction(mc.Method);
                if (function1 != null)
                {
                    if (mc.Method.IsGenericMethod)
                    {
                        throw new InvalidOperationException(
                            string.Format("Invalid use of generic method '{0}' as user defined function.",
                                          mc.Method.Name));
                    }
                    if (function1.FunctionType == MetaFunctionType.TableValuedFunction)
                    {
                        return this.TranslateTableValuedFunction(mc, function1);
                    }
                    if (function1.FunctionType == MetaFunctionType.UserDefinedFunction)
                    {
                        List<SqlExpression> list1 = this.GetFunctionParameters(mc, function1);
                        return this._sql.FunctionCall(mc.Method.ReturnType, function1.MappedName, list1, mc);
                    }
                }
            }
            SqlExpression expression2 = this.VisitExpression(mc.Object);
            SqlExpression[] expressionArray2 = new SqlExpression[mc.Parameters.Count];
            for (int index = 0, max = expressionArray2.Length; index < max; index++)
            {
                expressionArray2[index] = this.VisitExpression(mc.Parameters[index]);
            }
            return this._sql.MethodCall(mc.Method, expression2, expressionArray2, this._dominatingExpression);
        }

        private SqlExpression VisitNew(NewExpression qn)
        {
            MetaTable table2 = this._services.Model.GetTable(qn.Type);
            MetaType type2 = (table2 != null)
                                 ? table2.RowType.GetInheritanceType(qn.Type)
                                 : this._services.Model.GetUnmappedType(qn.Type);
            SqlExpression[] expressionArray2 = null;
            if ((qn.Type == typeof(decimal)) && (qn.Args.Count == 1))
            {
                return (this.VisitCast(Expression.Cast(qn.Args[0], typeof(decimal))) as SqlExpression);
            }
            if (qn.Args.Count > 0)
            {
                expressionArray2 = new SqlExpression[qn.Args.Count];

                for (int index = 0, max = qn.Args.Count; index < max; index++)
                {
                    expressionArray2[index] = this.VisitExpression(qn.Args[index]);
                }
            }
            return this._sql.New(type2, qn.Constructor, expressionArray2, null, this._dominatingExpression);
        }

        private SqlExpression VisitNewArrayInit(NewArrayExpression arr)
        {
            SqlExpression[] expressionArray2 = new SqlExpression[arr.Expressions.Count];
            for (int index = 0, max = expressionArray2.Length; index < max; index++)
            {
                expressionArray2[index] = this.VisitExpression(arr.Expressions[index]);
            }
            return new SqlClientArray(arr.Type, this._typeProvider.From(arr.Type), expressionArray2,
                                      this._dominatingExpression);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="ofType"></param>
        /// <returns></returns>
        private SqlSelect VisitOfType(Expression sequence, Type ofType)
        {
            SqlSelect select2 = this.LockSelect(this.VisitSequence(sequence));
            SqlAliasRef ref2 = (SqlAliasRef)select2.Selection;
            select2.Selection = new SqlUnary(SqlNodeType.Treat, ofType, this._typeProvider.From(ofType), ref2,
                                             this._dominatingExpression);
            select2 = this.LockSelect(select2);
            ref2 = (SqlAliasRef)select2.Selection;
            select2.Where = this._sql.AndAccumulate(select2.Where,
                                                   this._sql.Unary(SqlNodeType.IsNotNull, ref2, this._dominatingExpression));
            return select2;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="expression"></param>
        /// <param name="orderType"></param>
        /// <returns></returns>
        private SqlSelect VisitOrderBy(Expression sequence, LambdaExpression expression, SqlOrderType orderType)
        {
            SqlSelect select2 = this.VisitSequence(sequence);
            if ((select2.Selection.NodeType != SqlNodeType.AliasRef) || (select2.OrderBy.Count > 0))
            {
                SqlAlias alias1 = new SqlAlias(select2);
                SqlAliasRef ref1 = new SqlAliasRef(alias1);
                select2 = new SqlSelect(ref1, alias1, this._dominatingExpression);
            }
            this._map[expression.Parameters[0]] = select2.Selection;
            SqlExpression expression2 = this.VisitExpression(expression.Body);
            select2.OrderBy.Add(new SqlOrderExpression(orderType, expression2));
            return select2;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private SqlNode VisitParameter(ParameterExpression p)
        {
            return this._map[p];
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="lambda"></param>
        /// <param name="isAny"></param>
        /// <returns></returns>
        private SqlNode VisitQuantifier(Expression sequence, LambdaExpression lambda, bool isAny)
        {
            SqlSelect select2 = this.VisitSequence(sequence);
            SqlAlias alias2 = new SqlAlias(select2);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            if (lambda != null)
            {
                this._map[lambda.Parameters[0]] = ref2;
            }
            SqlExpression expression2 = (lambda != null) ? this.VisitExpression(lambda.Body) : null;
            if (isAny)
            {
                if (this._outerNode)
                {
                    SqlSelect select3 = new SqlSelect(ref2, alias2, this._dominatingExpression);
                    select3.Top = this._sql.Literal(1, this._dominatingExpression);
                    select3.Where = expression2;
                    select3.OrderingType = SqlOrderingType.Never;
                    SqlAlias alias3 = new SqlAlias(select3);
                    SqlUnary unary1 = this._sql.UnaryConvert(typeof(bool), this._typeProvider.From(typeof(bool)),
                                                            this.GetAggregate(SqlNodeType.Count, typeof(decimal), null),
                                                            this._dominatingExpression);
                    return new SqlSelect(unary1, alias3, this._dominatingExpression);
                }
                SqlSelect select5 = new SqlSelect(ref2, alias2, this._dominatingExpression);
                select5.Where = expression2;
                select5.OrderingType = SqlOrderingType.Never;
                return this._sql.SubSelect(SqlNodeType.Exists, select5);
            }
            SqlSelect select6 = new SqlSelect(ref2, alias2, this._dominatingExpression);
            SqlSubSelect select7 = this._sql.SubSelect(SqlNodeType.Exists, select6);
            select6.Where = this._sql.Unary(SqlNodeType.Not, expression2, this._dominatingExpression);
            return this._sql.Unary(SqlNodeType.Not, select7, this._dominatingExpression);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        private SqlSelect VisitSelect(Expression sequence, LambdaExpression selector)
        {
            SqlSelect select3 = this.VisitSequence(sequence);
            SqlAlias alias2 = new SqlAlias(select3);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            this._map[selector.Parameters[0]] = ref2;
            SqlNode node2 = this.Visit(selector.Body);
            SqlSelect select4 = node2 as SqlSelect;
            if (select4 == null)
            {
                SqlExpression expression2 = node2 as SqlExpression;
                if (expression2 == null)
                {
                    throw new Exception("Bad projection in Select()");
                }
                return new SqlSelect(expression2, alias2, this._dominatingExpression);
            }
            return new SqlSelect(this._sql.SubSelect(SqlNodeType.Multiset, select4), alias2, this._dominatingExpression);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="lambda"></param>
        /// <returns></returns>
        private SqlSelect VisitSelectMany(Expression sequence, LambdaExpression lambda)
        {
            SqlSelect select2 = this.VisitSequence(sequence);
            SqlAlias alias3 = new SqlAlias(select2);
            SqlAliasRef ref3 = new SqlAliasRef(alias3);
            this._map[lambda.Parameters[0]] = ref3;
            SqlNode node2 = this.Visit(lambda.Body);
            if ((node2.NodeType == SqlNodeType.Element) || (node2.NodeType == SqlNodeType.Multiset))
            {
                node2 = ((SqlSubSelect)node2).Select;
            }
            SqlAlias alias4 = new SqlAlias(node2);
            SqlAliasRef ref4 = new SqlAliasRef(alias4);
            SqlJoin join2 = new SqlJoin(SqlJoinType.CrossApply, alias3, alias4, null, this._dominatingExpression);
            return new SqlSelect(ref4, join2, this._dominatingExpression);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        private SqlSelect VisitSequence(Expression exp)
        {
            return this.CoerceToSequence(this.Visit(exp));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mc"></param>
        /// <returns></returns>
        private SqlNode VisitSequenceOperatorCall(MethodCallExpression mc)
        {
            Type type2 = mc.Method.DeclaringType;
            if (((type2 != typeof(Sequence)) && (type2 != typeof(Queryable))) &&
                (type2 != typeof(DataQueryExtensions)))
            {
                throw new InvalidOperationException(
                    "VisitSequenceOperatorCall can only be called for Sequence, Querayble or DLinq.DataQueryExtensions");
            }
            string text1 = mc.Method.Name;
            if (text1 != null)
            {
                int num1;
                if (_operators == null)
                {
                    Dictionary<string, int> dictionary1 = new Dictionary<string, int>(0x24);
                    dictionary1.Add("Select", 0);
                    dictionary1.Add("SelectMany", 1);
                    dictionary1.Add("Join", 2);
                    dictionary1.Add("GroupJoin", 3);
                    dictionary1.Add("DefaultIfEmpty", 4);
                    dictionary1.Add("OfType", 5);
                    dictionary1.Add("Where", 6);
                    dictionary1.Add("First", 7);
                    dictionary1.Add("FirstOrDefault", 8);
                    dictionary1.Add("Single", 9);
                    dictionary1.Add("SingleOrDefault", 10);
                    dictionary1.Add("Distinct", 11);
                    dictionary1.Add("Concat", 12);
                    dictionary1.Add("Union", 13);
                    dictionary1.Add("Intersect", 14);
                    dictionary1.Add("Except", 15);
                    dictionary1.Add("Any", 0x10);
                    dictionary1.Add("All", 0x11);
                    dictionary1.Add("Count", 0x12);
                    dictionary1.Add("LongCount", 0x13);
                    dictionary1.Add("Sum", 20);
                    dictionary1.Add("Min", 0x15);
                    dictionary1.Add("Max", 0x16);
                    dictionary1.Add("Average", 0x17);
                    dictionary1.Add("GroupBy", 0x18);
                    dictionary1.Add("OrderBy", 0x19);
                    dictionary1.Add("OrderByDescending", 0x1a);
                    dictionary1.Add("ThenBy", 0x1b);
                    dictionary1.Add("ThenByDescending", 0x1c);
                    dictionary1.Add("Take", 0x1d);
                    dictionary1.Add("Skip", 30);
                    dictionary1.Add("Including", 0x1f);
                    dictionary1.Add("Contains", 0x20);
                    dictionary1.Add("ToList", 0x21);
                    dictionary1.Add("ToSequence", 0x22);
                    dictionary1.Add("ToArray", 0x23);
                    _operators = dictionary1;
                }
                if (_operators.TryGetValue(text1, out num1))
                {
                    switch (num1)
                    {
                        case 0:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitSelect(mc.Parameters[0], (LambdaExpression)mc.Parameters[1]);
                            }
                            break;

                        case 1:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitSelectMany(mc.Parameters[0], (LambdaExpression)mc.Parameters[1]);
                            }
                            break;

                        case 2:
                            if ((((mc.Parameters.Count == 5) && (mc.Parameters[2] is LambdaExpression)) &&
                                 ((((LambdaExpression)mc.Parameters[2]).Parameters.Count == 1) &&
                                  (mc.Parameters[3] is LambdaExpression))) &&
                                (((((LambdaExpression)mc.Parameters[3]).Parameters.Count == 1) &&
                                  (mc.Parameters[4] is LambdaExpression)) &&
                                 (((LambdaExpression)mc.Parameters[4]).Parameters.Count == 2)))
                            {
                                return this.VisitJoin(mc.Parameters[0], mc.Parameters[1],
                                                      (LambdaExpression)mc.Parameters[2],
                                                      (LambdaExpression)mc.Parameters[3],
                                                      (LambdaExpression)mc.Parameters[4]);
                            }
                            break;

                        case 3:
                            if ((((mc.Parameters.Count == 5) && (mc.Parameters[2] is LambdaExpression)) &&
                                 ((((LambdaExpression)mc.Parameters[2]).Parameters.Count == 1) &&
                                  (mc.Parameters[3] is LambdaExpression))) &&
                                (((((LambdaExpression)mc.Parameters[3]).Parameters.Count == 1) &&
                                  (mc.Parameters[4] is LambdaExpression)) &&
                                 (((LambdaExpression)mc.Parameters[4]).Parameters.Count == 2)))
                            {
                                return this.VisitGroupJoin(mc.Parameters[0], mc.Parameters[1],
                                                           (LambdaExpression)mc.Parameters[2],
                                                           (LambdaExpression)mc.Parameters[3],
                                                           (LambdaExpression)mc.Parameters[4]);
                            }
                            break;

                        case 4:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitDefaultIfEmpty(mc.Parameters[0]);
                            }
                            break;

                        case 5:
                            if (mc.Parameters.Count == 1)
                            {
                                Type type3 = mc.Method.GetGenericArguments()[0];
                                return this.VisitOfType(mc.Parameters[0], type3);
                            }
                            break;

                        case 6:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitWhere(mc.Parameters[0], (LambdaExpression)mc.Parameters[1]);
                            }
                            break;

                        case 7:
                        case 8:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitFirst(mc.Parameters[0], null, true);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitFirst(mc.Parameters[0], (LambdaExpression)mc.Parameters[1], true);

                        case 9:
                        case 10:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitFirst(mc.Parameters[0], null, false);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitFirst(mc.Parameters[0], (LambdaExpression)mc.Parameters[1], false);

                        case 11:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitDistinct(mc.Parameters[0]);
                            }
                            break;

                        case 12:
                            if (mc.Parameters.Count == 2)
                            {
                                return this.VisitConcat(mc.Parameters[0], mc.Parameters[1]);
                            }
                            break;

                        case 13:
                            if (mc.Parameters.Count == 2)
                            {
                                return this.VisitUnion(mc.Parameters[0], mc.Parameters[1]);
                            }
                            break;

                        case 14:
                            if (mc.Parameters.Count == 2)
                            {
                                return this.VisitIntersect(mc.Parameters[0], mc.Parameters[1]);
                            }
                            break;

                        case 15:
                            if (mc.Parameters.Count == 2)
                            {
                                return this.VisitExcept(mc.Parameters[0], mc.Parameters[1]);
                            }
                            break;

                        case 0x10:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitQuantifier(mc.Parameters[0], null, true);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitQuantifier(mc.Parameters[0], (LambdaExpression)mc.Parameters[1], true);

                        case 0x11:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitQuantifier(mc.Parameters[0], (LambdaExpression)mc.Parameters[1], false);
                            }
                            break;

                        case 0x12:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitAggregate(mc.Parameters[0], null, SqlNodeType.Count, mc.Type);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitAggregate(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                       SqlNodeType.Count, mc.Type);

                        case 0x13:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitAggregate(mc.Parameters[0], null, SqlNodeType.LongCount, mc.Type);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitAggregate(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                       SqlNodeType.LongCount, mc.Type);

                        case 20:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitAggregate(mc.Parameters[0], null, SqlNodeType.Sum, mc.Type);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitAggregate(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                       SqlNodeType.Sum, mc.Type);

                        case 0x15:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitAggregate(mc.Parameters[0], null, SqlNodeType.Min, mc.Type);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitAggregate(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                       SqlNodeType.Min, mc.Type);

                        case 0x16:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitAggregate(mc.Parameters[0], null, SqlNodeType.Max, mc.Type);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitAggregate(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                       SqlNodeType.Max, mc.Type);

                        case 0x17:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.VisitAggregate(mc.Parameters[0], null, SqlNodeType.Avg, mc.Type);
                            }
                            if (((mc.Parameters.Count != 2) || !(mc.Parameters[1] is LambdaExpression)) ||
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count != 1))
                            {
                                break;
                            }
                            return this.VisitAggregate(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                       SqlNodeType.Avg, mc.Type);

                        case 0x18:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitGroupBy(mc.Parameters[0], (LambdaExpression)mc.Parameters[1], null);
                            }
                            if ((((mc.Parameters.Count == 3) && (mc.Parameters[1] is LambdaExpression)) &&
                                 ((((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1) &&
                                  (mc.Parameters[2] is LambdaExpression))) &&
                                (((LambdaExpression)mc.Parameters[2]).Parameters.Count == 1))
                            {
                                return this.VisitGroupBy(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                         (LambdaExpression)mc.Parameters[2]);
                            }
                            break;

                        case 0x19:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitOrderBy(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                         SqlOrderType.Ascending);
                            }
                            break;

                        case 0x1a:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitOrderBy(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                         SqlOrderType.Descending);
                            }
                            break;

                        case 0x1b:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitThenBy(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                        SqlOrderType.Ascending);
                            }
                            break;

                        case 0x1c:
                            if (((mc.Parameters.Count == 2) && (mc.Parameters[1] is LambdaExpression)) &&
                                (((LambdaExpression)mc.Parameters[1]).Parameters.Count == 1))
                            {
                                return this.VisitThenBy(mc.Parameters[0], (LambdaExpression)mc.Parameters[1],
                                                        SqlOrderType.Descending);
                            }
                            break;

                        case 0x1d:
                            if (mc.Parameters.Count == 2)
                            {
                                return this.VisitTake(mc.Parameters[0], mc.Parameters[1]);
                            }
                            break;

                        case 30:
                            if (mc.Parameters.Count == 2)
                            {
                                return this.VisitSkip(mc.Parameters[0], mc.Parameters[1]);
                            }
                            break;

                        case 0x1f:
                            if ((mc.Parameters.Count == 2) && (mc.Parameters[1] is NewArrayExpression))
                            {
                                return this.VisitIncluding(mc.Parameters[0],
                                                           ((NewArrayExpression)mc.Parameters[1]).Expressions);
                            }
                            break;

                        case 0x20:
                            if (mc.Parameters.Count == 2)
                            {
                                return this.VisitContains(mc.Parameters[0], mc.Parameters[1]);
                            }
                            break;

                        case 0x21:
                        case 0x22:
                        case 0x23:
                            if (mc.Parameters.Count == 1)
                            {
                                return this.Visit(mc.Parameters[0]);
                            }
                            break;
                    }
                }
            }
            throw new InvalidOperationException(string.Format("The query operator '{0}' is not supported by DLinq",
                                                              mc.Method.Name));
        }

        private SqlSelect VisitSkip(Expression sequence, Expression count)
        {
            SqlSelect select3 = this.LockSelect(this.VisitSequence(sequence));
            SqlExpression expression2 = this.VisitExpression(count);
            SqlAlias alias2 = new SqlAlias(select3);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            SqlDuplicator duplicator2 = new SqlDuplicator();
            SqlSelect select4 = (SqlSelect)duplicator2.Duplicate(select3);
            int num2 = Convert.ToInt32(this.Eval(expression2));
            if (num2 > 0)
            {
                select4.Top = this._sql.Literal(num2, this._dominatingExpression);
                SqlAlias alias3 = new SqlAlias(select4);
                SqlAliasRef ref3 = new SqlAliasRef(alias3);
                SqlSelect select5 = new SqlSelect(ref3, alias3, this._dominatingExpression);
                select5.Where = this._sql.Binary(SqlNodeType.EQ, ref2, ref3);
                SqlSubSelect select6 = this._sql.SubSelect(SqlNodeType.Exists, select5);
                SqlSelect select7 = new SqlSelect(ref2, alias2, this._dominatingExpression);
                select7.Where = this._sql.Unary(SqlNodeType.Not, select6, this._dominatingExpression);
                return select7;
            }
            return select3;
        }


        private SqlSelect VisitTake(Expression sequence, Expression count)
        {
            SqlSelect select2 = this.LockSelect(this.VisitSequence(sequence));
            select2.Top = this._sql.Literal(this.Eval(this.VisitExpression(count)), this._dominatingExpression);
            return select2;
        }

        private SqlSelect VisitThenBy(Expression sequence, LambdaExpression expression, SqlOrderType orderType)
        {
            SqlSelect select2 = this.VisitSequence(sequence);
            this._map[expression.Parameters[0]] = select2.Selection;
            SqlExpression expression2 = this.VisitExpression(expression.Body);
            select2.OrderBy.Add(new SqlOrderExpression(orderType, expression2));
            return select2;
        }

        private SqlNode VisitTypeBinary(TypeBinaryExpression b)
        {
            SqlExpression expression3 = this.VisitExpression(b.Expression);
            if (b.NodeType == ExpressionType.Is)
            {
                Type type1 = b.TypeOperand;
                return this._sql.Unary(SqlNodeType.IsNotNull,
                                      new SqlUnary(SqlNodeType.Treat, type1, this._typeProvider.From(type1), expression3,
                                                   this._dominatingExpression), this._dominatingExpression);
            }
            throw new Exception("Type Binary operator not recognized");
        }


        private SqlNode VisitUnary(UnaryExpression u)
        {
            SqlExpression expression3 = this.VisitExpression(u.Operand);
            SqlExpression expression4 = null;
            switch (u.NodeType)
            {
                case ExpressionType.As:
                    return this._sql.Unary(SqlNodeType.Treat, expression3, this._dominatingExpression);

                case ExpressionType.BitwiseAnd:
                    return expression4;

                case ExpressionType.BitwiseNot:
                    return this._sql.Unary(SqlNodeType.BitNot, expression3, this._dominatingExpression);

                case ExpressionType.Negate:
                    return this._sql.Unary(SqlNodeType.Negate, expression3, this._dominatingExpression);

                case ExpressionType.Not:
                    return this._sql.Unary(SqlNodeType.Not, expression3, this._dominatingExpression);
            }
            return expression4;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source1"></param>
        /// <param name="source2"></param>
        /// <returns></returns>
        private SqlNode VisitUnion(Expression source1, Expression source2)
        {
            SqlSelect select3 = this.VisitSequence(source1);
            SqlSelect select4 = this.VisitSequence(source2);
            SqlUnion union2 = new SqlUnion(select3, select4, false);
            SqlAlias alias2 = new SqlAlias(union2);
            SqlAliasRef ref2 = new SqlAliasRef(alias2);
            return new SqlSelect(ref2, alias2, this._dominatingExpression);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="qu"></param>
        /// <returns></returns>
        private SqlStatement VisitUpdate(UpdateCommand qu)
        {
            SqlStatement statement1;
            bool flag2 = this._allowDeferred;
            this._allowDeferred = false;
            try
            {
                Expression expression1 = qu.Sequence;
                if (qu.Check != null)
                {
                    expression1 = QueryExpression.Where(expression1, qu.Check);
                }
                SqlSelect select1 = this.VisitSequence(expression1);
                List<SqlAssign> list1 = new List<SqlAssign>(qu.Assignments.Count);
                foreach (UpdateAssign assign1 in qu.Assignments)
                {
                    SqlMemberAssign assign2 = new SqlMemberAssign(assign1.Member,
                                                                  this.VisitExpression(assign1.Expression));
                    SqlMember member1 = this._sql.Member(select1.Selection, assign2.Member);
                    SqlAssign assign3 = new SqlAssign(member1, assign2.Expression, qu);
                    list1.Add(assign3);
                }
                SqlUpdate update1 = new SqlUpdate(select1, list1, qu);
                if (qu.Result == null)
                {
                    return update1;
                }
                expression1 = qu.Sequence;
                SqlSelect select2 = this.VisitSequence(expression1);
                OracleRefCursor cursor = new OracleRefCursor(expression1);
                cursor.Select = this.VisitSequence(expression1);
                cursor.Parameter = new SqlParameter(typeof(object), this._typeProvider.Parse("cursor"), "p", expression1);
                SqlBlock block1 = new SqlBlock(qu);
                block1.Statements.Add(update1);
                block1.Statements.Add(cursor);
                statement1 = block1;
            }
            finally
            {
                this._allowDeferred = flag2;
            }
            return statement1;
        }


        private SqlUserQuery VisitUserQuery(UserQueryExpression qt)
        {
            SqlExpression[] expressionArray2 = new SqlExpression[qt.Args.Count];
            int num1 = 0;
            int num2 = expressionArray2.Length;
            while (num1 < num2)
            {
                expressionArray2[num1] = this.VisitExpression(qt.Args[num1]);
                num1++;
            }
            SqlUserQuery query2 = new SqlUserQuery(qt.Query, null, expressionArray2, this._dominatingExpression);
            if (qt.Type != typeof(void))
            {
                Type type1 = TypeSystem.GetElementType(qt.Type);
                MetaTable table1 = this._services.Model.GetTable(type1);
                MetaType type2 = (table1 != null)
                                     ? table1.RowType.GetInheritanceType(type1)
                                     : this._services.Model.GetUnmappedType(type1);
                SqlUserRow row1 = new SqlUserRow(type2, this._typeProvider.GetApplicationType(1), query2,
                                                 this._dominatingExpression);
                query2.Projection = this._translator.BuildDefaultProjection(row1, type2,
                                                                           type2.IsEntity
                                                                               ? type2.GetPersistentDataMembers()
                                                                               : type2.GetDataMembers(),
                                                                           this._allowDeferred, qt);
            }
            return query2;
        }

        private SqlSelect VisitWhere(Expression sequence, LambdaExpression predicate)
        {
            SqlSelect select2 = this.LockSelect(this.VisitSequence(sequence));
            this._map[predicate.Parameters[0]] = select2.Selection;
            select2.Where = this.VisitExpression(predicate.Body);
            return select2;
        }

        #endregion

        #region Nested classes

        /// <summary>
        /// 
        /// </summary>
        private class IncludeException : Exception
        {
            #region Constructors

            /// <summary>
            /// 
            /// </summary>
            internal IncludeException()
                : base("Including expression must refer to an immediate property")
            {
            }

            #endregion
        }

        #endregion
    }
}